/* ===========================================================
 * JFreeChart : a free chart library for the Java(tm) platform
 * ===========================================================
 *
 * (C) Copyright 2000-2009, by Object Refinery Limited and Contributors.
 *
 * Project Info:  http://www.jfree.org/jfreechart/index.html
 *
 * This library is free software; you can redistribute it and/or modify it
 * under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation; either version 2.1 of the License, or
 * (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
 * License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301,
 * USA.
 *
 * [Java is a trademark or registered trademark of Sun Microsystems, Inc.
 * in the United States and other countries.]
 *
 * ----------------------
 * RendererUtilities.java
 * ----------------------
 * (C) Copyright 2007-2009, by Object Refinery Limited.
 *
 * Original Author:  David Gilbert (for Object Refinery Limited);
 * Contributor(s):   -;
 *
 * Changes
 * -------
 * 19-Apr-2007 : Version 1 (DG);
 * 27-Mar-2009 : Fixed results for unsorted datasets (DG);
 *
 */

package org.jfree.chart.renderer;

import java.util.ArrayList;
import java.util.List;

import org.jfree.data.DomainOrder;
import org.jfree.data.xy.XYDataset;

import visiopuce.graph.XYFloatingBarDataset;

/**
 * Utility methods related to the rendering process.
 * 
 * @since 1.0.6
 */
public class RendererUtilities {

	/**
	 * Finds the lower index of the range of live items in the specified data
	 * series.
	 * 
	 * @param dataset
	 *            the dataset (<code>null</code> not permitted).
	 * @param series
	 *            the series index.
	 * @param xLow
	 *            the lowest x-value in the live range.
	 * @param xHigh
	 *            the highest x-value in the live range.
	 * 
	 * @return The index of the required item.
	 * 
	 * @since 1.0.6
	 * 
	 * @see #findLiveItemsUpperBound(XYDataset, int, double, double)
	 */
	public static int findLiveItemsLowerBound(XYDataset dataset, int series,
			double xLow, double xHigh) {
		if (dataset == null) {
			throw new IllegalArgumentException("Null 'dataset' argument.");
		}
		if (xLow >= xHigh) {
			throw new IllegalArgumentException("Requires xLow < xHigh.");
		}
		int itemCount = dataset.getItemCount(series);
		if (itemCount <= 1) {
			return 0;
		}
		if (dataset.getDomainOrder() == DomainOrder.ASCENDING) {
			// for data in ascending order by x-value, we are (broadly) looking
			// for the index of the highest x-value that is less than xLow
			int low = 0;
			int high = itemCount - 1;
			double lowValue = dataset.getXValue(series, low);
			if (lowValue >= xLow) {
				// special case where the lowest x-value is >= xLow
				return low;
			}
			double highValue = dataset.getXValue(series, high);
			if (highValue < xLow) {
				// special case where the highest x-value is < xLow
				return high;
			}
			while (high - low > 1) {
				int mid = (low + high) / 2;
				double midV = dataset.getXValue(series, mid);
				if (midV >= xLow) {
					high = mid;
				} else {
					low = mid;
				}
			}
			return high;
		} else if (dataset.getDomainOrder() == DomainOrder.DESCENDING) {
			// when the x-values are sorted in descending order, the lower
			// bound is found by calculating relative to the xHigh value
			int low = 0;
			int high = itemCount - 1;
			double lowValue = dataset.getXValue(series, low);
			if (lowValue <= xHigh) {
				return low;
			}
			double highValue = dataset.getXValue(series, high);
			if (highValue > xHigh) {
				return high;
			}
			while (high - low > 1) {
				int mid = (low + high) / 2;
				double midV = dataset.getXValue(series, mid);
				if (midV > xHigh) {
					low = mid;
				} else {
					high = mid;
				}
				mid = (low + high) / 2;
			}
			return high;
		} else {
			// we don't know anything about the ordering of the x-values,
			// but we can still skip any initial values that fall outside the
			// range...
			int index = 0;
			// skip any items that don't need including...
			double x = dataset.getXValue(series, index);
			while (index < itemCount && (x < xLow || x > xHigh)) {
				index++;
				if (index < itemCount) {
					x = dataset.getXValue(series, index);
				}
			}
			return Math.min(Math.max(0, index), itemCount - 1);
		}
	}

	/**
	 * Finds the upper index of the range of live items in the specified data
	 * series.
	 * 
	 * @param dataset
	 *            the dataset (<code>null</code> not permitted).
	 * @param series
	 *            the series index.
	 * @param xLow
	 *            the lowest x-value in the live range.
	 * @param xHigh
	 *            the highest x-value in the live range.
	 * 
	 * @return The index of the required item.
	 * 
	 * @since 1.0.6
	 * 
	 * @see #findLiveItemsLowerBound(XYDataset, int, double, double)
	 */
	public static int findLiveItemsUpperBound(XYDataset dataset, int series,
			double xLow, double xHigh) {
		if (dataset == null) {
			throw new IllegalArgumentException("Null 'dataset' argument.");
		}
		if (xLow >= xHigh) {
			throw new IllegalArgumentException("Requires xLow < xHigh.");
		}
		int itemCount = dataset.getItemCount(series);
		if (itemCount <= 1) {
			return 0;
		}
		if (dataset.getDomainOrder() == DomainOrder.ASCENDING) {
			int low = 0;
			int high = itemCount - 1;
			double lowValue = dataset.getXValue(series, low);
			if (lowValue > xHigh) {
				return low;
			}
			double highValue = dataset.getXValue(series, high);
			if (highValue <= xHigh) {
				return high;
			}
			int mid = (low + high) / 2;
			while (high - low > 1) {
				double midV = dataset.getXValue(series, mid);
				if (midV <= xHigh) {
					low = mid;
				} else {
					high = mid;
				}
				mid = (low + high) / 2;
			}
			return mid;
		} else if (dataset.getDomainOrder() == DomainOrder.DESCENDING) {
			// when the x-values are descending, the upper bound is found by
			// comparing against xLow
			int low = 0;
			int high = itemCount - 1;
			int mid = (low + high) / 2;
			double lowValue = dataset.getXValue(series, low);
			if (lowValue < xLow) {
				return low;
			}
			double highValue = dataset.getXValue(series, high);
			if (highValue >= xLow) {
				return high;
			}
			while (high - low > 1) {
				double midV = dataset.getXValue(series, mid);
				if (midV >= xLow) {
					low = mid;
				} else {
					high = mid;
				}
				mid = (low + high) / 2;
			}
			return mid;
		} else {
			// we don't know anything about the ordering of the x-values,
			// but we can still skip any trailing values that fall outside the
			// range...
			int index = itemCount - 1;
			// skip any items that don't need including...
			double x = dataset.getXValue(series, index);
			while (index >= 0 && (x < xLow || x > xHigh)) {
				index--;
				if (index >= 0) {
					x = dataset.getXValue(series, index);
				}
			}
			return Math.max(index, 0);
		}
	}

	/**
	 * Finds a range of item indices that is guaranteed to contain all the
	 * x-values from x0 to x1 (inclusive).
	 * 
	 * @param dataset
	 *            the dataset (<code>null</code> not permitted).
	 * @param series
	 *            the series index.
	 * @param xLow
	 *            the lower bound of the x-value range.
	 * @param xHigh
	 *            the upper bound of the x-value range.
	 * 
	 * @return The indices of the boundary items.
	 */
	 public static int[] findLiveItems(XYDataset dataset, int series,
	 double xLow, double xHigh) {
	 // here we could probably be a little faster by searching for both
	 // indices simultaneously, but I'll look at that later if it seems
	 // like it matters...
	 int i0 = findLiveItemsLowerBound(dataset, series, xLow, xHigh);
	 int i1 = findLiveItemsUpperBound(dataset, series, xLow, xHigh);
	 if (i0 > i1) {
	 i0 = i1;
	 }
	 return new int[] {i0, i1};
	 }
	 
	 
	public static List<Integer> findVisbleItems(
			XYFloatingBarDataset floatingBarDataset, int series, double xLow,
			double xHigh) {
		List<Integer> result = new ArrayList<Integer>();
		if (floatingBarDataset == null) {
			throw new IllegalArgumentException("Null 'dataset' argument.");
		}
		if (xLow >= xHigh) {
			throw new IllegalArgumentException("Requires xLow < xHigh.");
		}
		int itemCount = floatingBarDataset.getItemCount(series);
		if (itemCount < 1) {
			return result;
		}
		// we don't know anything about the ordering of the x-values,
		// but we can still skip any trailing values that fall outside the
		// range...
		// skip any items that don't need including...
		double start = 0;
		double end = 0;
		for (int index = 0; index < itemCount; index++) {
			 start = floatingBarDataset.getStartXValue(series,index);
			 end = floatingBarDataset.getEndXValue(series, index);
			if (start <= xHigh && end >= xLow){
				result.add(index);
			} 
		}
		return result;
	}
}
